package org.testis.utils;

import java.io.IOException;
import java.io.InputStream;


/**
 * Defines a class to read input stream with a timeout option
 * @author nurhat
 */
public class PolledInputStream extends InputStream
{

    public PolledInputStream(InputStream input,
                             long timeout)
    {
        this.input = input;
        this.timeout = timeout;
    }


    @Override
    public int available() throws IOException
    {
        return input.available();
    }


    @Override
    public void close() throws IOException
    {
        input.close();
    }


    @Override
    public void mark(int readlimit)
    {
        input.mark(readlimit);
    }


    @Override
    public boolean markSupported()
    {
        return input.markSupported();
    }


    public int read() throws IOException
    {
        waitForAvailable();
        return input.read();
    }


    @Override
    public int read(byte[] b) throws IOException
    {
        return read(b,
                    0,
                    b.length);
    }


    @Override
    public int read(byte[] b,
                    int off,
                    int len) throws IOException
    {
        waitForAvailable();
        int n = available();
        return input.read(b,
                          off,
                          Math.min(len,
                                   n));
    }


    @Override
    public void reset() throws IOException
    {
        input.reset();
    }


    @Override
    public long skip(long n) throws IOException
    {
        return input.skip(n);
    }
    private InputStream input;
    private long timeout;


    private void sleep(long time)
    {
        try {
            Thread.sleep(Math.max(0,
                                  time));
        } catch (InterruptedException ignore) {
        }
    }


    private void waitForAvailable() throws IOException
    {
        long until = System.currentTimeMillis() + timeout;
        while (available() == 0) {
            if (System.currentTimeMillis() > until) {
                throw new IOException("input timed out");
            }
            sleep(100);
        }
    }
}
